package cn.uncode.rpc.core.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.List;

import cn.uncode.rpc.cluster.ClusterSupport;
import cn.uncode.rpc.common.CommonConstant;
import cn.uncode.rpc.core.DefaultInvoker;
import cn.uncode.rpc.core.Exporter;
import cn.uncode.rpc.core.Factory;
import cn.uncode.rpc.core.Invoker;
import cn.uncode.rpc.core.Protocol;
import cn.uncode.rpc.core.URL;
import cn.uncode.rpc.core.URLParam;
import cn.uncode.rpc.core.protocol.ProxyProtocol;
import cn.uncode.rpc.exception.FrameworkException;
import cn.uncode.rpc.registry.Registry;
import cn.uncode.rpc.registry.RegistryFactory;
import cn.uncode.rpc.spi.ExtensionLoader;
import cn.uncode.rpc.spi.SpiMeta;
import cn.uncode.rpc.util.StringTools;



@SpiMeta(name = CommonConstant.DEFAULT_VALUE)
public class DefaultFactory implements Factory {
	
	@SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clz, InvocationHandler invocationHandler) {
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {clz}, invocationHandler);
    }

	@Override
	public <T> Exporter<T> getExport(Class<T> interfaceClass, T ref, List<URL> registryUrls) {
		String serviceStr = StringTools.urlDecode(registryUrls.get(0).getParameter(URLParam.EMBED.getName()));
        URL serviceUrl = URL.valueOf(serviceStr);

        // export service
        // 利用protocol decorator来增加filter特性
        String protocolName = serviceUrl.getProtocol();
        Protocol protocol = new ProxyProtocol(ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(protocolName));
        Invoker<T> provider = new DefaultInvoker<T>(ref, serviceUrl, interfaceClass);
        provider.init();
        
        Exporter<T> exporter = protocol.export(provider, serviceUrl);

        // register service
        register(registryUrls, serviceUrl);

        return exporter;
	}
	
	
	private void register(List<URL> registryUrls, URL serviceUrl) {

        for (URL url : registryUrls) {
            // 根据check参数的设置，register失败可能会抛异常，上层应该知晓
            RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getExtension(url.getProtocol());
            if (registryFactory == null) {
                throw new FrameworkException("register error! Could not find extension for registry protocol:" + url.getProtocol()
                                + ", make sure registry module for " + url.getProtocol() + " is in classpath!");
            }
            Registry registry = registryFactory.getRegistry(url);
            registry.register(serviceUrl);
        }
    }

	@Override
	public <T> ClusterSupport<T> getClusterSupport(Class<T> interfaceClass, List<URL> registryUrls) {
		ClusterSupport<T> clusterSupport = new ClusterSupport<T>(interfaceClass, registryUrls);
		clusterSupport.init();

		return clusterSupport;
	}


}
